package com.hulk.ratel.common.optlocking;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Component;




/**
 * @Author: cmt
 * @E-mail: 29572320@qq.com
 * @Date: Create in 2018/1/24 上午11:38
 * @Version: 1.0.0
 * @Modify by:
 * Class description: 乐观锁处理
 *
 */

@Slf4j
@Aspect
@Component
public class OptimisticLockingFailureExecutor implements Ordered {

    private static final int DEFAULT_MAX_RETRIES = 3;


    private int maxRetries = DEFAULT_MAX_RETRIES;


    private int order = 1;

    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    @Pointcut("@annotation(RetryOnOptimisticLockingFailure)")
    public void retryOnOptFailure() {
        // pointcut mark

    }

    @Around("retryOnOptFailure()")
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        int numAttempts = 0;
        do {
            numAttempts++;
            try {
                return pjp.proceed();

            } catch (OptimisticLockingFailureException /*| PessimisticLockingFailureException*/ ex) {

                log.error("optimisticLock attempts count :" +numAttempts);
                if (numAttempts > maxRetries) {
                    //log failure information, and throw exception
                    throw ex;
                } else {
                    //log failure information for audit/reference
                    //will try recovery
                }

            }
        } while (numAttempts <= this.maxRetries);

        return null;
    }
}